/*
 * Copyright 2011 Todd Bealmear
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.dd0t.android.fbct;

import java.util.ArrayList;
import java.util.List;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import com.facebook.android.AsyncFacebookRunner;
import com.facebook.android.BaseRequestListener;
import com.facebook.android.Facebook;
import com.facebook.android.FacebookError;
import com.facebook.android.LoginButton;
import com.facebook.android.SessionEvents;
import com.facebook.android.SessionEvents.AuthListener;
import com.facebook.android.SessionEvents.LogoutListener;
import com.facebook.android.SessionStore;
import com.facebook.android.Util;

import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapActivity;
import com.google.android.maps.MapController;
import com.google.android.maps.MapView;
import com.google.android.maps.Overlay;
import com.google.android.maps.OverlayItem;

import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationManager;
import android.os.Bundle;
import android.util.Log;

/**
 * Activity class for FBCheckinThingy
 * @version 1.0.0
 * @author Todd Bealmear, <a href="http://dd0t.com">dd0t.com</a>
 */
public class FBCheckinThingy extends MapActivity {
	// Make this Context available to FBCTMarkerOverlay
	public static Context mContext;
	
	// Overlay stuff
	List<Overlay> mapOverlays;
	FBCTMarkerOverlay markerLayer;
	ArrayList<OverlayItem> overlays = new ArrayList<OverlayItem>();
	
	// Facebook Application ID
	public static final String APP_ID = "185734978114238";
	Facebook mFacebook;
	AsyncFacebookRunner mAsyncRunner;
	// Uses Facebook's LoginButton class - see class for documentation
	LoginButton mLoginButton;
	
	/**
	 * onCreate method for the MapActivity
	 * @param savedInstanceState A savedInstanceState Bundle.
	 */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		mContext = this;
		setContentView(R.layout.main);
		
		// Bind the LoginButton
		mLoginButton = (LoginButton)findViewById(R.id.login);
		
		// Set up map stuff
		MapView mapView = (MapView)findViewById(R.id.map);
		mapView.setSatellite(true);
		MapController mapController = mapView.getController();
		mapController.animateTo(getCurrentLocation());
		mapController.setZoom(10);
		
		// Set up overlay stuff
		mapOverlays = mapView.getOverlays();
		Drawable drawable = this.getResources().getDrawable(R.drawable.icon);
		markerLayer = new FBCTMarkerOverlay(drawable);
		
		// Set up Facebook stuff
		mFacebook = new Facebook(APP_ID);
		mAsyncRunner = new AsyncFacebookRunner(mFacebook);
		
		// Set up Facebook session stuff
		SessionStore.restore(mFacebook, this);
		SessionEvents.addAuthListener(new FBCTAuthListener());
		SessionEvents.addLogoutListener(new FBCTLogoutListener());
		mLoginButton.init(this, mFacebook, new String[] {"user_checkins"});	
		
		// Make the request to the Graph
		mAsyncRunner.request("me/checkins", new FBCTRequestListener());
	}
	
	/**
	 * Handles Single-Sign-On
	 */
	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		mFacebook.authorizeCallback(requestCode, resultCode, data);
	}
	
	/**
	 * No route to display in this app.
	 * @return False since we're not displaying a route.
	 */
	@Override
	protected boolean isRouteDisplayed() {
		return false;
	}
	
	/**
	 * Determines the device's current location, but does not display it.
	 * Used for centering the view on the device's location.
	 * @return A GeoPoint object that contains the lat/long coordinates for the device's location.
	 */
	private GeoPoint getCurrentLocation() {
		LocationManager mLocationManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
		Criteria mCriteria = new Criteria();
		mCriteria.setAccuracy(Criteria.ACCURACY_COARSE);
		mCriteria.setPowerRequirement(Criteria.POWER_LOW);
		String mLocationProvider = mLocationManager.getBestProvider(mCriteria, true);
		Location mLocation = mLocationManager.getLastKnownLocation(mLocationProvider);

		int mLat = (int)(mLocation.getLatitude()*1E6);
		int mLong = (int)(mLocation.getLongitude()*1E6);
		return new GeoPoint(mLat, mLong);
	}
	
	/**
	 * AuthListener implementation to handle authorization success or failure.
	 */
	public class FBCTAuthListener implements AuthListener {
		/**
		 * Handles a successful authorization.
		 */
		public void onAuthSucceed() {
			// Redundancy of Graph call is necessary here
			mAsyncRunner.request("me/checkins", new FBCTRequestListener());
		}

		/**
		 * Handles a failed authorization.
		 */
		public void onAuthFail(String error) {
			// Log it, yo!
			Log.v("FBCTActivity", "Authorization Failure: " + error);			
		}
	}
	
	/**
	 * LogoutListener implementation to handle Logout success or failure.
	 * We don't want to do anything at Logout, so we'll ust return out of these methods.
	 */
	public class FBCTLogoutListener implements LogoutListener {
		public void onLogoutBegin() {
			// Do Nothing
			return;
		}
		public void onLogoutFinish() {
			// Do Nothing
			return;
		}
	}
	
	/**
	 * BaseRequestListener implementation to handle our call to the Graph.
	 */
	public class FBCTRequestListener extends BaseRequestListener {
		/**
		 * Manipulates the data returned by the Graph call.
		 * 
		 * The madness below will make more sense if we can see an example of the raw JSON
		 * Here is one of the JSON objects contained within the greater JSON array:
		 * {
         *	"id": "",
         *	"from": {
         *   	"name": "Todd Bealmear",
         *  	"id": ""
         *	},
         *	"place": {
         *   	"id": "111461018893747",
         *   	"name": "In-N-Out Burger",
         *   	"location": {
         *     		"street": "3711 E Broadway Blvd",
         *     		"city": "Tucson",
         *     		"state": "AZ",
         *     		"country": "United States",
         *     		"zip": "85716-5409",
         *     		"latitude": 32.221737,
         *     		"longitude": -110.913515
         *  	}
         *	},
         *	"application": {
         *  	"name": "Facebook for Android",
         *  	"id": "350685531728"
         *	},
         *	"created_time": "2011-01-23T00:28:15+0000"
      	 * }
		 */
		public void onComplete(final String response, final Object state) {
			try {
				JSONObject json = Util.parseJson(response); // Create a JSONObject from the Graph's raw JSON
				JSONArray jArray = json.getJSONArray("data"); // Individual checkins are contained in an array, so let's create a JSONArray from the JSONObject
				for (int i = 0; i < jArray.length(); i++) { // Let's iterate!
					JSONObject outerPlace = jArray.getJSONObject(i); // Base of the JSONObject we want to pull data from
					JSONObject place = outerPlace.getJSONObject("place"); // Create a JSONObject for the "place" sub-object
					String placeName = place.getString("name"); // The name of the place
					JSONObject placeLocation = place.getJSONObject("location"); // Create a JSONObject for the "location" sub-sub-object
					int lat = (int) (placeLocation.getDouble("latitude")*1E6); // The place's latitude
					int lon = (int) (placeLocation.getDouble("longitude")*1E6); // The place's longitude
					// TODO: Convert date into more readable format (e.g., "1/25/2011 at 2:37 PM")
					String date = outerPlace.getString("created_time"); // The date/time of the checkin
					overlays.add(new OverlayItem(new GeoPoint(lat, lon), placeName, "Checked in on: " + date)); // Add the place's details to the ArrayList of OverlayItems
				}

				// Pass the values back to the main thread
				FBCheckinThingy.this.runOnUiThread(new Runnable() {
					public void run() {
						// Iterate through the OverlayItems
						for (int i = 0; i < overlays.size(); i++) {
							markerLayer.add(overlays.get(i));
						}
						mapOverlays.add(markerLayer);
					}
				});
			} catch (JSONException e) {
				Log.w("FBCTActivity", e.getMessage());
			} catch (FacebookError e) {
				Log.w("FBCTActivity", e.getMessage());
			}
		}
	}
}
